#pragma once
#include <intrin.h>
#include <stdio.h>
#include <assert.h>
#include "debug_constants.h"

enum COUNT_ID
{
	C_main,
	C_viewport_update,
	C_loop_other,
	C_total_loop,
	C1, 
	C2, 
	C3, 
	C4, 
	C5,
	C_graphics_text,
	C_input,
	count
};

const char * COUNT_STRINGS[COUNT_ID::count] = 
{
	"main___________",
	"viewport_update",
	"loop_other_____",
	"total_loop_____",
	"C1_____________",
	"C2_____________",
	"C3_____________",
	"C4_____________",
	"C5_____________",
	"text_graphics__",
	"input__________"
};

struct CounterData
{
	unsigned long long last_cycle_measurement[255];
	unsigned long long cycles[255];
	unsigned int calls[255];
	//expand this for time as well?
};

long long _GetCycleCount()
{
	return __rdtsc();
}

void counter_start(CounterData * cd,COUNT_ID id)
{
	if (DEBUG_MODE){assert(cd);}

	cd->last_cycle_measurement[(int)id] = _GetCycleCount();

}

void counter_end(CounterData * cd, COUNT_ID id)
{
	if (DEBUG_MODE){assert(cd);}
	cd->cycles[(int)id] += _GetCycleCount() - cd->last_cycle_measurement[(int)id];
	cd->calls[(int)id]++;
}

void counter_update(CounterData *cd)
{
	if (DEBUG_MODE){assert(cd);}
	if (DEBUG_MODE){assert(cd->calls[COUNT_ID::C_total_loop] == 1);}

	for (int i = 0; i < COUNT_ID::count; i++)
	{
		cd->calls[i] = 0;
		cd->cycles[i] = 0;
	}
}

/*
struct CounterInfo
{
	unsigned int index;
	unsigned long long cycle_count;
	unsigned int calls;
}
*/

double counter_get_contribution(CounterData * cd, COUNT_ID cid)
{
	long long total_cycles = cd->cycles[COUNT_ID::C_total_loop];
	double Result = (double)cd->cycles[(int)cid]/(double)total_cycles;
	return Result;
}

void counter_print(CounterData * cd)
{
	if (DEBUG_MODE){assert(cd);}
	if (DEBUG_MODE){assert(cd->calls[COUNT_ID::C_total_loop] == 1);}

	long long total_cycles = cd->cycles[COUNT_ID::C_total_loop];
	for (int i = 0; i < COUNT_ID::count; i++)
	{
		if (cd->calls[i] != 0)
		{
			printf("[%d],\t%2.2e,\tx%d,\t%2.2e,\t%3.3f%%,\t%s, \t%lu, \t%lu \n",
					i,																//index
					(double)cd->cycles[i],											//cycle count
					cd->calls[i],													//calls
					(double)((double)cd->cycles[i] / (double)cd->calls[i]),			//cycles per game loop
					 (double)cd->cycles[i]/(double)total_cycles,					//percentage cycles
					 COUNT_STRINGS[i],												//index name
					(long long unsigned)cd->cycles[i],								//cycle count
					(long long unsigned)((double)cd->cycles[i] / (double)cd->calls[i]));	//cycles/loop
		}
	}
}